package cn.com.twoke.application.game.mario.core.engine;

import cn.com.twoke.application.game.mario.core.ecs.component.InputState;
import cn.com.twoke.application.game.mario.core.ecs.world.GameWorld;
import cn.com.twoke.application.game.mario.game.scene.SceneManager;
import lombok.extern.slf4j.Slf4j;

import java.awt.*;
import java.util.Timer;
import java.util.TimerTask;


@Slf4j
public abstract class ECSGame extends javax.swing.JFrame {
    protected final GameWorld world;
    protected final GamePanel gamePanel;
    protected final InputState inputState = new InputState();
    protected final SceneManager sceneManager = new SceneManager();
    protected boolean running = true;
    private Timer gameTimer;

    public ECSGame(String title, int width, int height) {
        setTitle(title);
        setSize(width, height);
        setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        // 创建游戏世界
        world = new GameWorld();
        // 初始化
        init(world);
        // 添加系统
        initGameSystem(world);
        // 创建实体
        initGameEntities(world);

        // 创建游戏面板
        gamePanel = initGamePanel();
        this.setLayout(new BorderLayout());
        add(gamePanel, BorderLayout.CENTER);


        // 启动游戏定时器
        gameTimer = new Timer("GameLoopTimer", true);
        gameTimer.scheduleAtFixedRate(new GameLoopTask(), 0, GameLoopTask.OPTIMAL_TIME);
    }
    
    /**
     * 窗口关闭时清理资源
     */
    @Override
    public void dispose() {
        running = false;
        if (gameTimer != null) {
            gameTimer.cancel();
        }
        world.cleanup();
        super.dispose();
    }

    protected GamePanel initGamePanel() {
        return new GamePanel(world.getEntities(), inputState, world.getRenderSystem());
    }

    protected abstract void init(GameWorld world);

    protected abstract void initGameSystem(GameWorld world);

    protected abstract void initGameEntities(GameWorld world);

    private  class GameLoopTask extends TimerTask {
        private long lastLoopTime = System.currentTimeMillis();
        private static final int TARGET_FPS = 60;
        private static final long OPTIMAL_TIME = 1000 / TARGET_FPS;

        @Override
        public void run() {
            if (!running) {
                this.cancel();
                return;
            }

            long now = System.currentTimeMillis();
            long updateLength = now - lastLoopTime;
            lastLoopTime = now;
            double delta = updateLength / ((double) OPTIMAL_TIME);
            
            // 更新游戏状态
            world.update(delta);

            // 在EDT中重绘
            javax.swing.SwingUtilities.invokeLater(gamePanel::repaint);
        }
    }

}